package com.app.permissionx;

import android.Manifest;
import android.content.Context;
import android.content.pm.PackageManager;
import android.content.pm.PermissionGroupInfo;
import android.content.pm.PermissionInfo;
import android.content.res.Configuration;
import android.graphics.PorterDuff;
import android.os.Build;
import android.os.Bundle;
import android.text.TextUtils;
import android.util.Log;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.Window;
import android.view.WindowManager;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;

import androidx.annotation.ColorInt;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;

import com.zndroid.permission.dialog.RationaleDialog;

import java.lang.ref.WeakReference;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

/**
 * @author lzy
 * @date : 2020/8/2 23:02
 */
public class DefaultDialog extends RationaleDialog {

    private final LinkedHashMap<String, String> permissionMap = new LinkedHashMap<>();
    private final List<String> permissions;
    private final String message, positiveText, negativeText;
    private Button negativeBtn;
    private Button positiveBtn;
    private final int lightColor;
    private final int darkColor;
    private LinearLayout permissionsLayout;
    private LinearLayout negativeLayout, positiveLayout;

    private final boolean showDescription;

    private final WeakReference<Context> context;

    public DefaultDialog(@NonNull Context context, List<String> permissions, String message,
                         boolean showDescription,
                         String positiveText, String negativeText,
                         @ColorInt int lightColor, @ColorInt int darkColor) {

        super(context, R.style.PermissionXDefaultDialog);

        this.message = message;
        this.positiveText = positiveText;
        this.negativeText = negativeText;
        this.permissions = permissions;
        this.context = new WeakReference<>(context);
        this.showDescription = showDescription;
        this.lightColor = lightColor;
        this.darkColor = darkColor;

        initPermissionPools();
    }

    /**
     * Check if the permission layout if empty.
     * It is possible if all the permissions passed in are invalid permission such as a string named
     * "hello world". We won't add these into permission layout.
     */
    public boolean isPermissionLayoutEmpty() {
        return permissionsLayout.getChildCount() == 0;
    }

    private void setupText() {
        if (!TextUtils.isEmpty(negativeText)) {
            negativeLayout.setVisibility(View.VISIBLE);
            negativeBtn.setText(negativeText);
        } else {
            negativeLayout.setVisibility(View.GONE);
        }

        if (!TextUtils.isEmpty(positiveText)) {
            positiveLayout.setVisibility(View.VISIBLE);
            positiveBtn.setText(positiveText);
        } else {
            positiveLayout.setVisibility(View.GONE);
        }
    }

    private void setShowMode() {
        if (isDarkTheme()) {
            if (darkColor != -1) {
                positiveBtn.setTextColor(darkColor);
                negativeBtn.setTextColor(darkColor);
            }
        } else {
            if (lightColor != -1) {
                positiveBtn.setTextColor(lightColor);
                negativeBtn.setTextColor(lightColor);
            }
        }
    }

    private boolean isDarkTheme() {
        int flag = getContext().getResources().getConfiguration().uiMode & Configuration.UI_MODE_NIGHT_MASK;
        return flag == Configuration.UI_MODE_NIGHT_YES;
    }

    private void setupWindow() {
        Window window = getWindow();
        assert window != null;
        WindowManager.LayoutParams lp = window.getAttributes();
        lp.gravity = Gravity.CENTER;
        int width = context.get().getResources().getDisplayMetrics().widthPixels;
        int height = context.get().getResources().getDisplayMetrics().heightPixels;
        if (width < height) {
            lp.width = (int) (context.get().getResources().getDisplayMetrics().widthPixels * 0.86);
        } else {
            lp.width = (int) (context.get().getResources().getDisplayMetrics().widthPixels * 0.6);
        }
    }

    private void initPermissionPools(){
        initPermissionCommon();
        initPermissionJellyBean();
        initPermissionM();
        initPermissionO();
        initPermissionP();
        initPermissionQ();
    }

    /**
     * API >= 29, Android Q
     * */
    private void initPermissionQ() {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
            permissionMap.put(Manifest.permission.ACCESS_BACKGROUND_LOCATION, Manifest.permission_group.LOCATION);
            permissionMap.put(Manifest.permission.ACTIVITY_RECOGNITION, Manifest.permission_group.ACTIVITY_RECOGNITION);
            permissionMap.put(Manifest.permission.ACCESS_MEDIA_LOCATION, Manifest.permission_group.STORAGE);
        }
    }

    /**
     * API >= 28, Android P
     * */
    private void initPermissionP() {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
            permissionMap.put(Manifest.permission.READ_CALL_LOG, Manifest.permission_group.CALL_LOG);
            permissionMap.put(Manifest.permission.WRITE_CALL_LOG, Manifest.permission_group.CALL_LOG);
            permissionMap.put(Manifest.permission.PROCESS_OUTGOING_CALLS, Manifest.permission_group.CALL_LOG);

            permissionMap.put(Manifest.permission.ACCEPT_HANDOVER, Manifest.permission_group.PHONE);
        }
    }

    /**
     * API >= 26, Android O
     * */
    private void initPermissionO() {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            permissionMap.put(Manifest.permission.READ_PHONE_NUMBERS, Manifest.permission_group.PHONE);
            permissionMap.put(Manifest.permission.ANSWER_PHONE_CALLS, Manifest.permission_group.PHONE);
        }
    }

    /**
     * API >= 23, Android M
     * */
    private void initPermissionM() {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            permissionMap.put(Manifest.permission.READ_CONTACTS, Manifest.permission_group.CONTACTS);
            permissionMap.put(Manifest.permission.WRITE_CONTACTS, Manifest.permission_group.CONTACTS);
            permissionMap.put(Manifest.permission.GET_ACCOUNTS, Manifest.permission_group.CONTACTS);

            permissionMap.put(Manifest.permission.READ_PHONE_STATE, Manifest.permission_group.PHONE);

            permissionMap.put(Manifest.permission.CALL_PHONE, Manifest.permission_group.PHONE);
            permissionMap.put(Manifest.permission.ADD_VOICEMAIL, Manifest.permission_group.PHONE);
            permissionMap.put(Manifest.permission.USE_SIP, Manifest.permission_group.PHONE);

            permissionMap.put(Manifest.permission.BODY_SENSORS, Manifest.permission_group.SENSORS);

            permissionMap.put(Manifest.permission.SEND_SMS, Manifest.permission_group.SMS);
            permissionMap.put(Manifest.permission.RECEIVE_SMS, Manifest.permission_group.SMS);
            permissionMap.put(Manifest.permission.READ_SMS, Manifest.permission_group.SMS);
            permissionMap.put(Manifest.permission.RECEIVE_WAP_PUSH, Manifest.permission_group.SMS);
            permissionMap.put(Manifest.permission.RECEIVE_MMS, Manifest.permission_group.SMS);
        }
    }

    /**
     * API >= 17, Android M
     * */
    private void initPermissionJellyBean() {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
            permissionMap.put(Manifest.permission.READ_CALENDAR, Manifest.permission_group.CALENDAR);
            permissionMap.put(Manifest.permission.WRITE_CALENDAR, Manifest.permission_group.CALENDAR);

            permissionMap.put(Manifest.permission.CAMERA, Manifest.permission_group.CAMERA);

            permissionMap.put(Manifest.permission.RECORD_AUDIO, Manifest.permission_group.MICROPHONE);
        }
    }

    /**
     * since android common permission
     * */
    private void initPermissionCommon() {
        permissionMap.put(Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission_group.LOCATION);
        permissionMap.put(Manifest.permission.ACCESS_COARSE_LOCATION, Manifest.permission_group.LOCATION);

        permissionMap.put(Manifest.permission.READ_EXTERNAL_STORAGE, Manifest.permission_group.STORAGE);
        permissionMap.put(Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission_group.STORAGE);
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.permissionx_default_dialog_layout);

        TextView textView = findViewById(R.id.messageText);
        textView.setText(message);
        positiveBtn = findViewById(R.id.positiveBtn);
        negativeBtn = findViewById(R.id.negativeBtn);
        permissionsLayout = findViewById(R.id.permissionsLayout);
        negativeLayout = findViewById(R.id.negativeLayout);
        positiveLayout = findViewById(R.id.positiveLayout);

        setupWindow();
        setupText();
        setShowMode();
        buildPermissionsLayout();
    }

    @NonNull
    @Override
    public View getPositiveButton() {
        return positiveBtn;
    }

    @Nullable
    @Override
    public View getNegativeButton() {
        return negativeBtn;
    }

    @NonNull
    @Override
    public List<String> getPermissionsToRequest() {
        return permissions;
    }

    private void buildPermissionsLayout() {
        HashSet<String> groupSet = new HashSet<>();

        for (String p : permissions) {
            String permissionGroup = null;
            Set<Map.Entry<String,String>> entries = permissionMap.entrySet();
            Iterator<Map.Entry<String,String>> iterator = entries.iterator();
            while (iterator.hasNext()) {
                Map.Entry<String, String> entry = (Map.Entry<String, String>) iterator.next();
                if (entry.getKey().equals(p)) {
                    if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) {
                        PermissionInfo permissionInfo;
                        try {
                            permissionInfo = context.get().getPackageManager().getPermissionInfo(p, 0);
                            permissionGroup = permissionInfo.group;
                        } catch (PackageManager.NameNotFoundException e) {
                            permissionGroup = entry.getValue();
                        }
                    } else {
                        permissionGroup = entry.getValue();
                    }
                }
            }

            boolean isOnlyOnce = (PermissionMap.allSpecialPermissions().contains(p) && !(groupSet.contains(p)))
                    || (permissionGroup != null && !groupSet.contains(permissionGroup));

            if (isOnlyOnce) {
                permissionsLayout.addView(drawItem(p, permissionGroup));
                groupSet.add(permissionGroup);
            }

        }
    }

    private LinearLayout drawItem(String p, String permissionGroup) {
        LinearLayout linearLayout = (LinearLayout) LayoutInflater.from(context.get())
                .inflate(R.layout.permissionx_permission_item, permissionsLayout, false);

        TextView textView = linearLayout.findViewById(R.id.permissionText);
        ImageView permissionIcon = linearLayout.findViewById(R.id.permissionIcon);
        try {
            if (showDescription) {
                //特殊权限展示（需要跳转到系统专属页面开启的）
                if (Manifest.permission.ACCESS_BACKGROUND_LOCATION.equalsIgnoreCase(p)) {
                    permissionIcon.setImageResource(R.drawable.permissionx_ic_location);
                    textView.setText(context.get().getResources().getString(R.string.permissionx_access_background_location));

                }
                if (Manifest.permission.SYSTEM_ALERT_WINDOW.equalsIgnoreCase(p)) {
                    permissionIcon.setImageResource(R.drawable.permissionx_ic_alert);
                    textView.setText(context.get().getResources().getString(R.string.permissionx_system_alert_window));

                }
                if (Manifest.permission.WRITE_SETTINGS.equalsIgnoreCase(p)) {
                    permissionIcon.setImageResource(R.drawable.permissionx_ic_setting);
                    textView.setText(context.get().getResources().getString(R.string.permissionx_write_settings));

                }
                if (Manifest.permission.MANAGE_EXTERNAL_STORAGE.equalsIgnoreCase(p)) {
                    permissionIcon.setImageResource(R.drawable.permissionx_ic_storage);
                    textView.setText(context.get().getResources().getString(R.string.permissionx_manage_external_storage));

                }
                if (Manifest.permission.REQUEST_INSTALL_PACKAGES.equalsIgnoreCase(p)) {
                    permissionIcon.setImageResource(R.drawable.permissionx_ic_install);
                    textView.setText(context.get().getResources().getString(R.string.permissionx_request_install_packages));
                }
                //其他权限展示
                else {
                    PermissionGroupInfo groupInfo = context.get().getPackageManager().getPermissionGroupInfo(permissionGroup, 0);
                    permissionIcon.setImageResource(groupInfo.icon);
                    textView.setText(showDescription ?
                            groupInfo.loadDescription(context.get().getPackageManager()) :
                            groupInfo.loadLabel(context.get().getPackageManager()));
                }
            } else {
                permissionIcon.setVisibility(View.GONE);
            }

            if (isDarkTheme()) {
                if (darkColor != -1) {
                    permissionIcon.setColorFilter(darkColor, PorterDuff.Mode.SRC_ATOP);
                }
            } else {
                if (lightColor != -1) {
                    permissionIcon.setColorFilter(lightColor, PorterDuff.Mode.SRC_ATOP);
                }
            }
        } catch (PackageManager.NameNotFoundException e) {
            Log.e("permissionx", "NameNotFoundException");
        }

        return linearLayout;
    }
}
